#!/bin/bash

VERSION=0.3
EMBEDFILE=""
INPUTFILE=""
OUTPUTFILE=""
STDINBINARY="mpv"
STEGMETHOD="read"
STEGFILE=""

stegembed_file () {
    echo "[cysteg] hiding \"$2\" in \"$1\" via file method..."
    steggen "$2"
    if cat "$STEGFILE" >> "$1"
    then
        echo "[cysteg] successfully embedded stegdata!"
        stegclean temp
    else
        echo "[cysteg] [ERROR] failed to embed stegdata!"
        exit 1
    fi
    exit 0
}

stegembed_exif () {
    echo "[cysteg] hiding $2 in $1 via exif method..."
    steggen "$2"

    if (( $(stat -c%s "$STEGFILE") > 65515 ))
    then
        echo "[cysteg] [ERROR] input file too large, keep the image under 64KiB!"
        stegclean temp
        exit 1
    fi

    if exiftool -overwrite_original "-comment<=$STEGFILE" "$1"
    then
        echo "[cysteg] successfully embedded exif stegdata!"
        stegclean temp
    else
        echo "[cysteg] [ERROR] writing exif comment failed!"
        exit 1
    fi
    exit 0
}

steggen () {
    echo "[cysteg] generating stegdata for $1..."
    STEGFILE="$1".cysteg

    if [[ ! -e "$STEGFILE" ]]
    then
        if echo "@CYSTEG_START@" >> "$STEGFILE" && \
        base64 "$1" >> "$STEGFILE" && \
        echo "@CYSTEG_END@" >> "$STEGFILE"
        then
            echo "[cysteg] generating stegdata finnished!"
        else
            echo "[cysteg] [ERROR] error writing stegdata!"
            exit 1
        fi
    else
        echo "[cysteg] [ERROR] stegdata not writable!"
        exit 1
    fi
}

stegclean () {
    if [[ $1 == temp && "$STEGFILE" != "" ]]
    then
        rm -v "$STEGFILE"
    fi
}

stegread () {
    # very slow (use ramdisk?)
    echo "[cysteg] searching for stegdata in $1..."
    STEGSKIP=$(dd if="$1" bs=1 status=none | grep -aob "@CYSTEG_START@")
    STEGEND=$(dd if="$1" bs=1 status=none | grep -aob "@CYSTEG_END@")

    if [[ $STEGSKIP == "" || $STEGEND == "" ]]
    then
        echo "[cysteg] [ERROR] no stegdata found in $1"
        exit 1
    fi
    STEGSKIP=${STEGSKIP%:*}
    STEGEND=${STEGEND%:*}
    (( STEGSKIP += 15 ))
    (( STEGCOUNT = STEGEND-STEGSKIP ))

    echo "[cysteg] found stegdata from bytes $STEGSKIP to $STEGEND"
    dd if="$1" bs=1 skip=$STEGSKIP count=$STEGCOUNT status=none | base64 -d | "$STDINBINARY" -
    exit 0
}

print_help () {
	printf " \
-m                    Steganography method\n \
   read               Read stegdata from input (default)\n \
   file               Embed embedfile in input\n \
   exif               Embed embedfile (<64KiB) as exif comment in input\n \
-i <filename>         Input/Coverfile\n \
-e <filename>         Embedfile\n \
-o <filename>         Output if reading a stegfile input (not implemented!)\n \
-a <application>      Application to read from stdin (default: mpv)\n"
	exit 0
}

echo "cysteg version $VERSION"
while getopts i:e:o:a:m:h OPTION
do
	case "${OPTION}"
	in
        m) STEGMETHOD="${OPTARG}" ;;
		i) INPUTFILE="$(readlink -f "${OPTARG}")" ;;
		e) EMBEDFILE="$(readlink -f "${OPTARG}")" ;;
		o) OUTPUTFILE="$(readlink -f "${OPTARG}")" ;;
        a) STDINBINARY="${OPTARG}" ;;
        h) print_help ;;
	esac
done

if [[ $STEGMETHOD == "file" && -r "$EMBEDFILE" && -w "$INPUTFILE" ]]
then
    stegembed_file "$INPUTFILE" "$EMBEDFILE"
elif [[ $STEGMETHOD == "exif" && -r "$EMBEDFILE" && -w "$INPUTFILE" ]]
then
    stegembed_exif "$INPUTFILE" "$EMBEDFILE"
elif [[ $STEGMETHOD == "read" && -r "$INPUTFILE" ]]
then
    stegread "$INPUTFILE"
elif [[ $STEGMETHOD != "read" ]]
then
    echo "[cysteg] [ERROR] invalid steganography method!"
    exit 1
fi

print_help
